using System;
using GameFrameworkLibraly.BaseObjects;
using GameFrameworkLibraly.Helpers.GeometryHelpers;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input.Touch;

namespace GameFrameworkLibraly.Controls
{
    public class ManipulatorControl:Control
    {
        /// <summary>
        /// Texture that will be drawn as a foreground
        /// </summary>
        public Texture2D ForeTexture { get; set; }


        private const double ScaleOfForeTexture = 0.3;
        private const double ScaleOfBackTexture = 0.7;


        private Vector2 _positionStartDragging;
        private Vector2 _positionCurrentDragging;

        private bool _isBeingDragged;
        

        /// <summary>
        /// Creates a new instance of manipulator
        /// </summary>
        /// <param name="backTexture">Texture that will be drawn as a background</param>
        /// <param name="foreTexture">Texture that will be drawn as a foreground</param>
        /// <param name="destinationRectangle">Where the manipulator will be located</param>
        public ManipulatorControl(MyGame game, Texture2D backTexture, Texture2D foreTexture, Rectangle destinationRectangle):base(game)
        {
            BackgroundTexture = backTexture;
            ForeTexture = foreTexture;
            DestinationRectangle = destinationRectangle;
            RecalculateRectanglesForTextures();
            BackColorFilter = new Color(255, 255, 255, 200);
            ForeColor = new Color(255, 255, 255, 200);
        }

        private void RecalculateRectanglesForTextures()
        {
            ForeTextureRectangle =
                new Rectangle((int) (DestinationRectangle.Center.X - DestinationRectangle.Width*ScaleOfForeTexture/2),
                              (int) (DestinationRectangle.Center.Y - DestinationRectangle.Height*ScaleOfForeTexture/2),
                              (int) (DestinationRectangle.Width*ScaleOfForeTexture),
                              (int) (DestinationRectangle.Height*ScaleOfForeTexture));
            BackTextureRectangle =
                new Rectangle(
                    (int)(DestinationRectangle.Center.X - DestinationRectangle.Width * ScaleOfBackTexture / 2),
                    (int)(DestinationRectangle.Center.Y - DestinationRectangle.Height * ScaleOfBackTexture / 2),
                    (int)(DestinationRectangle.Width * ScaleOfBackTexture),
                    (int)(DestinationRectangle.Height * ScaleOfBackTexture));
        }

        /// <summary>
        /// Occures when the foreground is being dragged
        /// </summary>
        public event EventHandler Dragged;

        private void InvokeDragged(EventArgs e)
        {
            EventHandler handler = Dragged;
            if (handler != null) handler(this, e);
        }

        /// <summary>
        /// Occures when dragging end
        /// </summary>
        public event EventHandler<DraggingEndEventArgs> DraggingEnd;

        private void InvokeDraggingEnd(DraggingEndEventArgs e)
        {
            EventHandler<DraggingEndEventArgs> handler = DraggingEnd;
            if (handler != null) handler(this, e);
        }

        /// <summary>
        /// Where the foretexture is located
        /// </summary>
        public Rectangle ForeTextureRectangle { get; private set; }

        /// <summary>
        /// Where the backtexture is located
        /// </summary>
        public Rectangle BackTextureRectangle { get; private set; }
        
        /// <summary>
        /// Gets the current value of manipulator
        /// </summary>
        public Vector2 Value
        {
            get
            {
                Vector2 vector2 = ForeTextureRectangle.Center.ToVector2()-DestinationRectangle.Center.ToVector2();
                vector2.X /= DestinationRectangle.Width/2;
                vector2.Y /= DestinationRectangle.Width/2;
                return vector2;
            }
        }

        /// <summary>
        /// Draws the control
        /// </summary>
        /// <param name="spriteBatch"></param>
        public override void Draw(SpriteBatch spriteBatch)
        {
            if (!Visible)
                return;
            spriteBatch.Draw(BackgroundTexture, BackTextureRectangle, BackColorFilter);
            spriteBatch.Draw(ForeTexture, ForeTextureRectangle, ForeColor);
        }
        
        /// <summary>
        /// Updates state of the control
        /// </summary>
        /// <param name="gameTime"></param>
        public override void Update(GameTime gameTime)
        {
            return;
        }

        /// <summary>
        /// Handles a touch and changes the state of this component if needed
        /// </summary>
        /// <param name="touch">Touch Location</param>
        /// <returns>True, if touch was handled</returns>
        public override bool ProcessTouch(TouchLocation touch)
        {
            if(!Enabled)
                return false;
            bool touchHandled = false;
            bool isInside = ForeTextureRectangle.Contains((int)touch.Position.X, (int)touch.Position.Y);
            switch (touch.State)
            {

                case TouchLocationState.Pressed:
                    if (isInside)
                    {
                        InvokeClick(EventArgs.Empty);
                        IsPressed = true;
                        TouchID = touch.Id;
                        touchHandled = true;

                        _positionStartDragging = _positionCurrentDragging = touch.Position;
                    }
                    break;
                case TouchLocationState.Moved:
                    if (TouchID.HasValue && TouchID.Value == touch.Id)
                    {
                        IsPressed = isInside;
                        touchHandled = true;

                        _isBeingDragged = true;
                        Rectangle rect = ForeTextureRectangle;
                        rect.Offset((int) (touch.Position.X - _positionCurrentDragging.X),
                                    (int) (touch.Position.Y - _positionCurrentDragging.Y));
                        if (rect.Intersects2CirclesInscribedInRectangles(BackTextureRectangle))
                            ForeTextureRectangle = rect;
                        InvokeDragged(EventArgs.Empty);
                        _positionCurrentDragging = touch.Position;
                    }
                    break;
                case TouchLocationState.Released:
                    if (TouchID.HasValue && TouchID.Value == touch.Id)
                    {
                        TouchID = null;
                        IsPressed = false;
                        touchHandled = true;
                        InvokeReleased(EventArgs.Empty);
                        if (_isBeingDragged)
                        {
                            InvokeDraggingEnd(
                                new DraggingEndEventArgs(_positionStartDragging, _positionCurrentDragging));
                            RecalculateRectanglesForTextures();
                        }
                        _isBeingDragged = false;
                    }
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }


            return touchHandled;
        }
       
    }
}
